package com.guonl.config.mybatis;

import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.cache.Cache;
import org.redisson.api.RReadWriteLock;
import org.redisson.api.RedissonClient;
import org.springframework.data.redis.connection.RedisServerCommands;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReadWriteLock;

@Slf4j
public class MybatisRedisCache implements Cache {
    // redisson 读写锁
    private final RReadWriteLock redissonReadWriteLock;
    // redisTemplate
    private final RedisTemplate redisTemplate;
    // 缓存Id
    private final String id;

    //过期时间 30分钟
    private final long expirationTime = 30;

    public MybatisRedisCache(String id) {
        this.id = id;
        //获取redisTemplate
        this.redisTemplate = SpringUtil.getBean(RedisTemplate.class);
        //创建读写锁
        this.redissonReadWriteLock = SpringUtil.getBean(RedissonClient.class).getReadWriteLock("mybatis-cache-lock:" + this.id);
    }

    @Override
    public void putObject(Object key, Object value) {
        //使用redis的Hash类型进行存储
        redisTemplate.opsForValue().set(getCacheKey(key), value, expirationTime, TimeUnit.MINUTES);
    }

    @Override
    public Object getObject(Object key) {
        try {
            //根据key从redis中获取数据
            Object cacheData = redisTemplate.opsForValue().get(getCacheKey(key));
            log.debug("[Mybatis 二级缓存]查询缓存,cacheKey={}", getCacheKey(key));
            return cacheData;
        } catch (Exception e) {
            log.error("缓存出错", e);
        }
        return null;
    }

    @Override
    public Object removeObject(Object key) {
        if (key != null) {
            log.debug("[Mybatis 二级缓存]删除缓存,cacheKey={}", getCacheKey(key));
            redisTemplate.delete(key.toString());
        }
        return null;
    }

    @Override
    public void clear() {
        log.debug("[Mybatis 二级缓存]清空缓存,id={}", getCachePrefix());
        Set keys = redisTemplate.keys(getCachePrefix() + ":*");
        redisTemplate.delete(keys);
    }

    @Override
    public int getSize() {
        Long size = (Long) redisTemplate.execute((RedisCallback<Long>) RedisServerCommands::dbSize);
        return size.intValue();
    }

    @Override
    public ReadWriteLock getReadWriteLock() {
        return this.redissonReadWriteLock;
    }

    @Override
    public String getId() {
        return this.id;
    }

    public String getCachePrefix() {
        return String.format("mybatis-cache:%s", this.id);
    }

    private String getCacheKey(Object key) {
        return getCachePrefix() + ":" + key;
    }
}
